package edu.northwestern.cbits.purple_robot_manager.probes.builtin; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.os.Parcelable; import android.preference.CheckBoxPreference; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; import com.google.android.gms.location.ActivityRecognition; import com.google.android.gms.location.ActivityRecognitionResult; import com.google.android.gms.location.DetectedActivity; import edu.northwestern.cbits.purple_robot_manager.ManagerService; import edu.northwestern.cbits.purple_robot_manager.R; import edu.northwestern.cbits.purple_robot_manager.activities.settings.FlexibleListPreference; import edu.northwestern.cbits.purple_robot_manager.logging.LogManager; import edu.northwestern.cbits.purple_robot_manager.probes.Probe; public class ActivityDetectionProbe extends Probe implements ConnectionCallbacks, OnConnectionFailedListener { private static final boolean DEFAULT_ENABLED = false; private static final String ACTIVITY_TYPE = "ACTIVITY_TYPE"; private static final String ACTIVITY_CONFIDENCE = "ACTIVITY_CONFIDENCE"; private static final String FREQUENCY = "config_probe_activity_detection_frequency"; private static final String ENABLED = "config_probe_activity_detection_enabled"; private static GoogleApiClient _apiClient = null; private Context _context = null; private long _lastFreq = 0; private PendingIntent _pendingIntent; @Override public String getPreferenceKey() { return "built_in_activity_detection"; } @Override public String name(Context context) { return "edu.northwestern.cbits.purple_robot_manager.probes.builtin.ActivityDetectionProbe"; } @Override public String title(Context context) { return context.getString(R.string.title_activity_detection_probe); } @Override public String probeCategory(Context context) { return context.getResources().getString(R.string.probe_misc_category); } @Override public void enable(Context context) { SharedPreferences prefs = Probe.getPreferences(context); Editor e = prefs.edit(); e.putBoolean(ActivityDetectionProbe.ENABLED, true); e.commit(); } @Override public void disable(Context context) { SharedPreferences prefs = Probe.getPreferences(context); Editor e = prefs.edit(); e.putBoolean(ActivityDetectionProbe.ENABLED, false); e.commit(); } @Override public boolean isEnabled(Context context) { final SharedPreferences prefs = Probe.getPreferences(context); boolean enabled = super.isEnabled(context); if (this._context == null) this._context = context.getApplicationContext(); if (enabled) enabled = prefs.getBoolean(ActivityDetectionProbe.ENABLED, ActivityDetectionProbe.DEFAULT_ENABLED); if (enabled) { long interval = Long.parseLong(prefs.getString(ActivityDetectionProbe.FREQUENCY, Probe.DEFAULT_FREQUENCY)); if (interval != this._lastFreq && ActivityDetectionProbe._apiClient != null && ActivityDetectionProbe._apiClient.isConnected()) { this._lastFreq = interval; if (ActivityDetectionProbe._apiClient.isConnected()) { try { ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(ActivityDetectionProbe._apiClient, this._pendingIntent); } catch (NullPointerException e) { LogManager.getInstance(context).logException(e); } ActivityDetectionProbe._apiClient.disconnect(); } ActivityDetectionProbe._apiClient.unregisterConnectionCallbacks(this); ActivityDetectionProbe._apiClient.unregisterConnectionFailedListener(this); ActivityDetectionProbe._apiClient = null; } if (ActivityDetectionProbe._apiClient == null) { ActivityDetectionProbe._apiClient = new GoogleApiClient.Builder(context) .addApi(ActivityRecognition.API).addConnectionCallbacks(this) .addOnConnectionFailedListener(this).build(); int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context); if (ConnectionResult.SUCCESS == resultCode) ActivityDetectionProbe._apiClient.connect(); } return true; } else if (ActivityDetectionProbe._apiClient != null && ActivityDetectionProbe._apiClient.isConnected()) { ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(ActivityDetectionProbe._apiClient, this._pendingIntent); ActivityDetectionProbe._apiClient.unregisterConnectionCallbacks(this); ActivityDetectionProbe._apiClient.unregisterConnectionFailedListener(this); ActivityDetectionProbe._apiClient.disconnect(); ActivityDetectionProbe._apiClient = null; } return false; } public static void activityDetected(Context context, Intent intent) { final SharedPreferences prefs = Probe.getPreferences(context); boolean enabled = prefs.getBoolean("config_probes_enabled", false); if (enabled) enabled = prefs.getBoolean(ActivityDetectionProbe.ENABLED, ActivityDetectionProbe.DEFAULT_ENABLED); if (enabled && ActivityRecognitionResult.hasResult(intent)) { ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent); ActivityDetectionProbe probe = new ActivityDetectionProbe(); Bundle bundle = new Bundle(); bundle.putString("PROBE", probe.name(context)); bundle.putLong("TIMESTAMP", result.getTime() / 1000); List<Bundle> activities = ActivityDetectionProbe.parseActivities(result.getProbableActivities()); bundle.putParcelableArrayList("ACTIVITIES", (ArrayList<? extends Parcelable>) activities); bundle.putInt("ACTIVITY_COUNT", activities.size()); DetectedActivity probable = result.getMostProbableActivity(); bundle.putString("MOST_PROBABLE_ACTIVITY", ActivityDetectionProbe.activityName(probable.getType())); bundle.putInt("MOST_PROBABLE_CONFIDENCE", probable.getConfidence()); probe.transmitData(context, bundle); } } public static String activityName(int activity) { switch (activity) { case DetectedActivity.IN_VEHICLE: return "IN_VEHICLE"; case DetectedActivity.ON_BICYCLE: return "ON_BICYCLE"; case DetectedActivity.ON_FOOT: return "ON_FOOT"; case DetectedActivity.STILL: return "STILL"; case DetectedActivity.TILTING: return "TILTING"; case DetectedActivity.RUNNING: return "RUNNING"; case DetectedActivity.WALKING: return "WALKING"; } return "UNKNOWN"; } public static List<Bundle> parseActivities(List<DetectedActivity> activities) { ArrayList<Bundle> bundles = new ArrayList<>(); for (DetectedActivity activity : activities) { Bundle b = new Bundle(); b.putString(ActivityDetectionProbe.ACTIVITY_TYPE, ActivityDetectionProbe.activityName(activity.getType())); b.putInt(ActivityDetectionProbe.ACTIVITY_CONFIDENCE, activity.getConfidence()); bundles.add(b); } return bundles; } @Override public String summarizeValue(Context context, Bundle bundle) { double confidence = bundle.getDouble("MOST_PROBABLE_CONFIDENCE"); String activity = bundle.getString("MOST_PROBABLE_ACTIVITY"); return context.getResources().getString(R.string.summary_activity_detection_probe, activity, confidence); } @Override public Map<String, Object> configuration(Context context) { Map<String, Object> map = super.configuration(context); SharedPreferences prefs = Probe.getPreferences(context); long freq = Long.parseLong(prefs.getString(ActivityDetectionProbe.FREQUENCY, Probe.DEFAULT_FREQUENCY)); map.put(Probe.PROBE_FREQUENCY, freq); return map; } @Override public void updateFromMap(Context context, Map<String, Object> params) { super.updateFromMap(context, params); if (params.containsKey(Probe.PROBE_FREQUENCY)) { Object frequency = params.get(Probe.PROBE_FREQUENCY); if (frequency instanceof Double) { frequency = ((Double) frequency).longValue(); } if (frequency instanceof Long) { SharedPreferences prefs = Probe.getPreferences(context); Editor e = prefs.edit(); e.putString(ActivityDetectionProbe.FREQUENCY, frequency.toString()); e.commit(); } } } @Override @SuppressWarnings("deprecation") public PreferenceScreen preferenceScreen(Context context, PreferenceManager manager) { PreferenceScreen screen = manager.createPreferenceScreen(context); screen.setTitle(this.title(context)); screen.setSummary(R.string.summary_activity_detection_probe_desc); CheckBoxPreference enabled = new CheckBoxPreference(context); enabled.setTitle(R.string.title_enable_probe); enabled.setKey(ActivityDetectionProbe.ENABLED); enabled.setDefaultValue(ActivityDetectionProbe.DEFAULT_ENABLED); screen.addPreference(enabled); FlexibleListPreference duration = new FlexibleListPreference(context); duration.setKey(ActivityDetectionProbe.FREQUENCY); duration.setDefaultValue(Probe.DEFAULT_FREQUENCY); duration.setEntryValues(R.array.probe_activity_recognition_frequency_values); duration.setEntries(R.array.probe_activity_recognition_frequency_labels); duration.setTitle(R.string.probe_frequency_label); screen.addPreference(duration); return screen; } @Override public JSONObject fetchSettings(Context context) { JSONObject settings = super.fetchSettings(context); try { JSONObject frequency = new JSONObject(); frequency.put(Probe.PROBE_TYPE, Probe.PROBE_TYPE_LONG); JSONArray values = new JSONArray(); String[] options = context.getResources().getStringArray( R.array.probe_activity_recognition_frequency_values); for (String option : options) { values.put(Long.parseLong(option)); } frequency.put(Probe.PROBE_VALUES, values); settings.put(Probe.PROBE_FREQUENCY, frequency); } catch (JSONException e) { LogManager.getInstance(context).logException(e); } return settings; } @Override public String summary(Context context) { return context.getString(R.string.summary_activity_detection_probe_desc); } @Override public void onConnected(Bundle bundle) { final SharedPreferences prefs = Probe.getPreferences(this._context); long interval = Long.parseLong(prefs.getString(ActivityDetectionProbe.FREQUENCY, Probe.DEFAULT_FREQUENCY)); Intent intent = new Intent(ManagerService.GOOGLE_PLAY_ACTIVITY_DETECTED); this._pendingIntent = PendingIntent.getService(this._context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); if (ActivityDetectionProbe._apiClient.isConnected()) ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(ActivityDetectionProbe._apiClient, interval, this._pendingIntent); else ActivityDetectionProbe._apiClient.connect(); } @Override public void onConnectionFailed(ConnectionResult result) { } @Override public void onConnectionSuspended(int cause) { // TODO Auto-generated method stub } }